package cn.dengta.webapp.user.model;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;

import cn.dengta.common.context.I18N;
import cn.dengta.context.model.RedisKey;
import cn.dengta.context.model.UserI18nKey;
import cn.dengta.context.web.ProxyRequest;
import lombok.Getter;
import lombok.Setter;
import me.codeplayer.util.*;
import org.springframework.data.redis.core.RedisTemplate;

public abstract class CaptchaUtil {

	/** 验证码的超时时间（分钟数） */
	public static final long TIMEOUT = 10;

	/**
	 * 多步验证
	 */
	public static String multistepCaptchaCheck(RedisTemplate<String, Object> template, String credential, String alias, String captcha) {
		if (StringUtil.isEmpty(captcha)) {
			return StringUtil.notEmpty(StringUtil.toString(template.opsForValue().get(RedisKey.AUTH_SMS_CAPTCHA + alias))) ? null : I18N.msg(UserI18nKey.CAPTCHA_ERROR_REGAIN);
		}
		return captchaCheck(template, credential, alias, captcha);
	}

	/**
	 * 校验邮箱验证码
	 *
	 * @return 1=校验通过；0=校验不通过，请重新输入；-1=校验不通过，请重新发送验证码
	 */
	protected static int verifyCaptcha(RedisTemplate<String, Object> redisTemplate, String credential, String captchaKey, String captcha) {
		if (redisTemplate != null) {
			final String value = (String) redisTemplate.opsForValue().get(captchaKey);
			if (StringUtil.notEmpty(value)) {
				CaptchaEntry entry = JSONUtil.parseObject(value, CaptchaEntry.class);

				final boolean OK = entry.remainErrorCount > 0
						&& entry.captcha.equals(captcha)
						&& (entry.credential.equalsIgnoreCase(credential) || PhoneArea.VN.has(credential) && PhoneArea.eqPhone(entry.credential, credential));
				if (OK) {
					return 1;
				}
				if (--entry.remainErrorCount > 0) {
					redisTemplate.opsForValue().setIfPresent(captchaKey, entry.toRedisValue(), entry.expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
					return 0;
				} else {
					redisTemplate.delete(captchaKey);
				}
			}
		}
		return -1;
	}

	public static String captchaCheck(RedisTemplate<String, Object> redisTemplate, String credential, String captchaKey, String captcha) {
		int result = verifyCaptcha(redisTemplate, credential, captchaKey, captcha);
		if (result > 0) {
			return null;
		}
		return result < 0 ? I18N.msg(UserI18nKey.CAPTCHA_ERROR_REGAIN) : I18N.msg(UserI18nKey.CAPTCHA_ERROR_RESUME_LOAD);
	}

	public static String loginKey(String ip) {
		return MsgBizType.TRY_LOGIN.alias + ip;
	}

	public static String emailBindKey(Long userId) {
		return MsgBizType.BIND.alias + userId;
	}

	public static String bizKey(@Nonnull String alias, @Nonnull String key) {
		return alias + key;
	}

	public static String bizKey(@Nonnull MsgBizType type, ProxyRequest q) {
		return bizKey(type.alias, isIp(type) ? q.getIP() : StringUtil.toString(q.getSessionUser().getId()));
	}

	public static boolean isIp(@Nonnull MsgBizType type) {
		return ArrayUtil.ins(type, MsgBizType.TRY_LOGIN, MsgBizType.REGISTER, MsgBizType.FIND_PWD, MsgBizType.PAY_RISK);
	}

	/**
	 * 移除当前存储的验证码
	 */
	public static void removeCode(RedisTemplate<String, Object> template, String alias) {
		if (template != null) {
			template.delete(alias);
		}
	}

	public static String smsPayRiskKey(String phone) {
		return MsgBizType.PAY_RISK.alias + phone;
	}

	@Getter
	@Setter
	public static class CaptchaEntry implements Serializable {

		MsgBizType bizType;
		public String credential;
		public String captcha;
		public int remainErrorCount;
		public long expireTime;

		public CaptchaEntry() {
		}

		public CaptchaEntry(MsgBizType bizType, String credential, String captcha) {
			this.bizType = bizType;
			this.credential = credential;
			this.captcha = captcha;
			this.remainErrorCount = 10;
			this.expireTime = System.currentTimeMillis() + TIMEOUT * EasyDate.MILLIS_OF_MINUTE;
		}

		public void setMail(String mail) {
			this.credential = mail;
		}

		public String toRedisValue() {
			return JSONUtil.encode(this);
		}

	}

}
